#pragma once
/*
 * spsc queue for one thread read and one thread write.
 */

#include <atomic>
#include <cstddef>

template <typename T>
class SPSCQueue {
public:
    explicit SPSCQueue(size_t capacity) : capacity_(capacity), mask_(capacity - 1) {
        if ((capacity & (capacity - 1)) != 0) {
            throw std::invalid_argument("Capacity must be a power of 2");
        }
        buffer_ = new T[capacity];
        read_index_.store(0, std::memory_order_relaxed);
        write_index_.store(0, std::memory_order_relaxed);
    }
    ~SPSCQueue() {
        if (buffer_ != nullptr) {
            delete[] buffer_;
        }
    }

    // forden copy constructor.
    SPSCQueue(const SPSCQueue&) = delete;
    SPSCQueue& operator=(const SPSCQueue&) = delete;

public:
    bool push(const T& value) {
        size_t write_index = write_index_.load(std::memory_order_relaxed);
        size_t next_slot = write_index + 1;
        if ((next_slot - read_index_.load(std::memory_order_acquire)) > mask_) {
            return false;
        }
        buffer_[write_index & mask_] = value;
        write_index_.store(next_slot, std::memory_order_release);
        return true;
    }

    bool pop(T& value) {
        size_t read_index = read_index_.load(std::memory_order_relaxed);
        if (read_index == write_index_.load(std::memory_order_acquire)) {
            return false;
        }
        value = buffer_[read_index & mask_];
        size_t next_slot = read_index + 1;
        read_index_.store(next_slot, std::memory_order_release);
        return true;
    }

    bool empty() const {
        return read_index_.load(std::memory_order_relaxed) == write_index_.load(std::memory_order_relaxed);
    }
    bool full() const {
        return (write_index_.load(std::memory_order_relaxed) + 1 - read_index_.load(std::memory_order_relaxed)) > mask_;
    }

private:
    T* buffer_;
    size_t capacity_;
    size_t mask_;

    // 对齐到缓存行，防止伪共享（False Sharing）
    // 确保读写下标不在同一个CPU缓存行中
    alignas(64) std::atomic<size_t> read_index_;
    alignas(64) std::atomic<size_t> write_index_;
};